type Object
    native;  // qt.Object

type Static [out Obj]
    opaque
    Obj;


type PropType
    protected
    String;

const PropTypeString: PropType :=
    'String'.{|PropType|};

const PropTypeBool: PropType :=
    'Bool'.{|PropType|};

const PropTypeMaybeNumber: PropType :=
    'MaybeNumber'.{|PropType|};


function get-property: [Obj < Object, T]
    &(Static[Obj], String, PropType) => T
    native 'qt-get-property';

function set-property: [T]
    &(Object, String, PropType, T) => Async
    native 'qt-set-property';

function bind-property: [T]
    & { object: Object,
        prop:   String,
        type:   PropType,
        source: Source[T] }
        => Async[never]
    & { object, prop, type, source } =>
        (source connect &(value) => {
            set-property (object, prop, type, value) });

function bind-property: [T]
    & { object: Object,
        prop:   String,
        type:   PropType,
        notify: String,
        sync:   Reactive[T] }
        => Async[never]
    & { object, prop, type, notify, sync } =>
        let write :=
            let source := { watch sync },
            { bind-property { object, prop, type, source } },
        let read :=
            let source := { Signal (object, notify, &(object) => {
                get-property (object, prop, type) }.[T]) },
            (source connect sync),
        { merge [read, write] };

